﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.ComponentModel;

namespace DeepEarth.Map.Core.Tiling
{

    public abstract class BaseTileSourceFactory
    {
        public abstract IList<MapMode> AvailableModes { get; }

		public bool IsValid(MapMode mode)
		{
			return AvailableModes.Contains(mode);
		}

		public bool IsValid(string modeIdentifier)
		{
			return AvailableModes.Any(x => x.Identifier == modeIdentifier);
		}

		public MapMode GetByIdentifier(string identifier)
		{
			return AvailableModes.FirstOrDefault(x => x.Identifier == identifier);
		}

		/// <summary>
		/// Validates if the mode is correct for the group.
		/// If the mode is not in this group, tries to find the mode with the same <see cref="MapMode.Identifier"/>
		/// and returns it.
		/// </summary>
		/// <remarks>
		/// When the <see cref="BaseTileSourceProvider.Mode"/> property is set, it is important to check if the concrete tile overlay
		/// can accept this mode.
		/// Also, the <paramref name="mode"/> can be translated from the XAML attribute string (by <see cref="MapModeTypeConverter"/>)
		/// and may only contain a valid identifier, so the <paramref name="mode"/> has to be coerced, and the "real" map mode 
		/// (with the same <see cref="MapMode.Identifier"/>) has to be returned from the method.
		/// </remarks>
		/// <param name="mode"></param>
		/// <returns>A valid map mode that can be used in the concrete tile overlay.</returns>
		/// <exception cref="ArgumentOutOfRangeException">
		/// when the <see cref="mode"/> is not correct  or the concrete tile overlay provider cannot accept this mode
		/// </exception>
		public MapMode ValidateAndCoerceMapMode(MapMode mode)
		{
			if (mode == null) throw new ArgumentNullException("mode");
			var realMapMode = AvailableModes.FirstOrDefault(x => x == mode)
			                  ?? AvailableModes.FirstOrDefault(x => x.Identifier == mode.Identifier);

			if (realMapMode == null)
				throw new ArgumentOutOfRangeException(
					String.Format("Map mode '{0}' is not valid for the group '{1}'", mode.Identifier, GetType().Name));

			return realMapMode;
		}

    	public abstract BaseTileSource CreateTileSource(MapMode mode);
    }
}
